from bs4 import BeautifulSoup
import requests


# 2. 配置网页加载器（支持动态渲染，如Vue/React构建的网页）
def load_web_content(url):
    # # 使用PlaywrightURLLoader替代PlaywrightWebBaseLoader
    # loader = WebBaseLoader(url)
    # docs = loader.load()
    # if not docs:
    #     raise Exception("未能加载任何文档内容")
    # return docs[0].page_content

    # 加载网页内容。静态网页用requests，动态网页暂时不考虑
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
    } # 添加User-Agent避免被网站拒绝
    # 发送请求并指定编码
    response = requests.get(url, headers=headers)
    response.encoding = response.apparent_encoding  # 自动识别网页内容编码，避免乱码

    # 原始网页内容
    print(response.text)
    # print(response.apparent_encoding)
    print("-------------------")

    # 解析 HTML - 使用 BeautifulSoup
    soup = BeautifulSoup(response.text, 'html.parser') # "html.parser"是Python内置解析器，无需额外安装

    # 输出网站内容
    # print(soup.text)
    # print("-------------------")

    # 过滤噪声元素
    # 在过滤前添加元素计数
    initial_count = len(soup.find_all(True))  # 获取所有标签的数量

    noise_tags = ["header", "footer", "nav", "script", "style", "iframe", "aside", "ad", "advertisement", "style"]
    removed_count = 0
    for tag in noise_tags:
        # 找到所有该标签，直接删除（decompose()会从DOM树中移除）
        for elem in soup.find_all(tag):
            removed_count += 1
            elem.decompose()
    # 过滤带特定类名的噪声（如"comment"评论区、"related"相关文章）
    for elem in soup.find_all(class_=["comment", "related", "share", "copy-code"]):
        removed_count += 1
        elem.decompose()

    # 过滤后的网站内容
    print(soup.text)
    # 输出移除的元素数量
    print(f"Removed {removed_count} elements out of {initial_count} total elements")

    print("-------------------")

    # 提取纯文本（get_text()会自动去除所有标签，只保留文字）
    # strip=False：保留段落间的换行
    # join + split：合并多余空格，让文本更整洁
    plain_text = soup.get_text(strip=False) # get_text() 与 text 的底层方法一致，不过方法可以接收参数
    # 清理冗余空格和空行（优化阅读体验）
    plain_text = "\n".join([line for line in plain_text.splitlines() if line.strip()])
    """
    plain_text.splitlines() - 将文本按行分割成一个列表，每一行成为列表中的一个元素
    line.strip() - 对每一行执行strip操作，移除行首和行尾的空白字符（包括空格、制表符、换行符等）
    if line.strip() - 过滤条件，只保留那些经过strip后仍然非空的行（即过滤掉空行）
    [line.strip() for line in plain_text.splitlines() if line.strip()] - 列表推导式，生成一个只包含非空且已去除首尾空白的行的列表
    "\n".join(...) - 用换行符将处理后的行重新连接成一个字符串
    
    即：
    移除文本中每一行的首尾空白字符
    过滤掉所有空行
    保持行与行之间的换行符分隔
    
    示例：
       这是第一行   

        这是第二行（前面有制表符）
       
       这是第三行
       
       处理后：
        这是第一行
        这是第二行（前面有制表符）
        这是第三行
    """

    # 输出纯文本
    print(plain_text)

    return plain_text


if __name__ == '__main__':
    url = "https://www.flysnow.org/2017/05/12/go-in-action-go-context"
    load_web_content(url)